home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
drdobbs
/
1990
/
06
/
fried.lst
< prev
next >
Wrap
File List
|
1990-05-02
|
14KB
|
560 lines
_ACCESSING HARDWARE FROM 80386 PROTECTED MODE: PART II_
by Stephen Fried
[LISTING ONE]
#include <dos.h> /* i.e. just like MS C */
void note();
main()
{
note(440,500);
}
void note(pitch, duration)
int pitch,duration;
{
int u,v;
union REGS regs;
unsigned int_count,int_duration,count,int_pitch;
int_pitch = 1190000/pitch;
int_duration = (duration*1821)/10000;
regs.x.ax = 0; /* call timer */
int86(0x1a, ®s, ®s);
int_count = regs.x.dx; /* internal count = lowest 16-bits of time*/
u = inp(0x61) | 3; /* Turn on channel 2 of 8255 using port 61h */
outp(0x61,u); /* send byte to back */
outp(0x43,0xb6); /* set up I/O register */
outp(0x42,(char) int_pitch); /* send freq to latch */
outp(0x42,(int_pitch >> 8));
do {
regs.x.ax = 0; /* use timer to get end of duration */
int86(0x1a, ®s, ®s);
count = regs.x.dx; /* use lowest 16-bits of count */
} while (count < int_duration + int_count);
v = inp(0x61) & 0xfc; /* turn off the sound */
outp(0x61,v);
}
[LISTING TWO]
#define outp(p,v) dx = p;al = v;asm(dx,al," out dx,al")
#define inp(p,v) dx = p;asm(dx," in al,dx",al);v = al
unsigned char x,y,page = 0; /* globals for pc_test */
void note();
main()
{
note(440,500);
}
void note(pitch, duration)
int pitch,duration;
{
reg$eax unsigned short ax;
reg$eax unsigned char al,x,y;
reg$edx unsigned short dx;
reg$ah unsigned char ah;
/* this section was added for play */
unsigned int_count,int_duration,count,int_pitch;
if (duration == 0) return;
int_duration = (duration*1821)/10000;
/* We left the original interrupt as a comment for comparison purposes */
/* regs.x.ax = 0; call timer */
/* int86(0x1a, ®s, ®s); */
/* int_count = regs.x.dx; internal count = lowest 16-bits of time*/
/* the inline assembly language is line for line identical in function
although there is an obvious difference in format. */
ax = 0;
asm(ax," int 01ah",dx);
int_count = dx;
if (pitch==0) goto time_it;
int_pitch = 1190000/pitch;
/* The port input is a little different using inline asm macros */
/* x = inp(0x61) | 3; the original code becomes */
inp(0x61,x); /* Turn on channel 2 of 8253 using port 61H */
x = x | 3; /* After read turn on lowest 2 bits */
+/* The outp macro looks just like the outp function */
outp(0x61,x); /* send byte to back */
outp(0x43,0xb6); /* set up I/O register */
outp(0x42,(char) int_pitch); /* send freq to latch */
outp(0x42,(int_pitch >> 8));
time_it:
do {
ax = 0; /* use timer to wait for end */
asm(ax," int 01ah",dx);
count = dx;
} while (count < int_duration + int_count);
inp(0x61,y); /* Turn off channel 2 */
y = y & 0xfc; /* use 1111 1100 to turn off lowest 2 bits only */
outp(0x61,y);
}
[LISTING THREE]
name sound4.c
.387
assume cs:codeseg
assume ds:dataseg
codeseg segment dword er use32 public 'code'
dataseg segment dword rw use32 public 'data'
dataseg ends
align 4
_note proc near
push edi
push esi
push ebx
mov ebx,[esp]+16
cmp dword ptr [esp]+20,0
jne L17 short
pop ebx
pop esi
pop edi
ret
align 4
L17:
mov ecx,10000
imul eax,[esp]+20,1821
cdq
idiv ecx
mov edi,eax
mov ax,0
int 01ah
movzx esi,dx
or ebx,ebx
jne L16 short
jmp L13
align 4
L16:
mov eax,1190000
cdq
idiv ebx
mov ebx,eax
mov dx,97
in al,dx
or al,3
mov dx,97
out dx,al
mov dx,67
mov al,182
out dx,al
mov dx,66
mov al,bl
out dx,al
mov dx,66
mov eax,ebx
shr eax,byte ptr 8
out dx,al
align 4
L14:
align 4
L13:
mov ax,0
int 01ah
movzx ecx,dx
mov eax,edi
add eax,esi
cmp eax,ecx
ja L13 short
mov dx,97
in al,dx
and al,252
mov dx,97
out dx,al
align 4
L9:
pop ebx
pop esi
pop edi
ret
align 4
_note endp
dataseg segment dword rw use32 public 'data'
;_ax ax local
;_al al local
;_x al local
;_y al local
;_dx dx local
;_ah ah local
;_int_count esi local
;_int_duration edi local
;_count ecx local
;_int_pitch ebx local
;parameters
;_pitch ebx local
;_duration [esp]+20 local
dataseg ends
end
[LISTING FOUR]
#include <stdio.h>
#include <dos1.h>
#include <ctype.h>
/* ***WARNING*** if you change the scale so that it starts
on middle C, instead of A, the resulting routine will
exhibit not only the look and feel of the BASIC PLAY
command, but its sound as well.
*/
#define aa 440 /* middle a = 440 */
#define as 469 /* a sharp */
#define bb 493
#define cc 523 /* middle c */
#define cs 556
#define dd 587
#define ds 624
#define ee 659
#define ff 698
#define fs 739
#define gg 783
#define gs 832
#define outp(p,v) dx = p;al = v;asm(dx,al," out dx,al")
#define inp(p,v) dx = p;asm(dx," in al,dx",al);v = al
unsigned char x,y,page = 0; /* globals for pc_test */
void note();
void look_ahead_and_toot();
void play();
int check_length();
int check_integer();
int gobble_dots();
/* the buffer for the notes to be input */
int pitch;
int count = 0; /* points to current location in string */
int length = 4; /* default is a quarter note */
int tempo = 240; /* = 120 beats per minute */
int duration = 60; /* = tempo/length =1/4 @ 120 bpm */
int shift = 0; /* current octave shift factor */
char c_note; /* the current note character used for diag */
main()
{ /* Stereo version of Heart and Soul for two PCs
lifted from a BASIC program Transcribed by
Michael Benjamin Fried - Age 11 */
/* bass line plays on first machine */
play( "T150L8O4CCEEAACCDDFFO3GG>BBO4");
play( "L8O4CCEEAACCDDFFO3GG>BBO4");
/* while melody plays on a second */
play( "O4L4CCC.P32C8B8A8B8C8D8P32");
play( "EEE.P32E8D8C8D8E8F8G.C.>A8<G8F8E8D8CB8Ao3G8FFGGo4");
}
void play(in_string)
char in_string[];
{
int temp_duration; /* gets set by L or change in l */
int temp_octave; /* holds temporary octave */
char n_note;
count = 0;
printf("note = %s \n",in_string);
while (c_note = in_string[count]){ /* loop till out of characters */
n_note = in_string[count+1]; /* look ahead 1 char now */
switch(c_note){ /* switch on current note */
case 'A': /* do a,a sharp and a flat */
case 'a':
pitch = aa; /* set the default to A natural */
if ((n_note == '#')||(n_note == '+')){
pitch = as; /* it was A sharp */
count++;
}
if (n_note == '-'){ /* it was A flat */
pitch = gs; /* A flat == G sharp */
count++;
}
look_ahead_and_toot(in_string); /* self explanatory */
break; /* line duration */
case 'B': /* B is just like A */
case 'b':
pitch = bb;
if ((n_note == '#')||(n_note == '+')){
pitch = cc; /* B sharp is actually C */
count++;
}
if (n_note == '-'){
pitch = as; /* B flat is A sharp */
count++;
}
look_ahead_and_toot(in_string);
break;
case 'C': /* C is just like A */
case 'c':
pitch = cc;
if ((n_note == '#')||(n_note == '+')){
pitch = cs;
count++;
}
if (n_note == '-'){ /* C flat is actually B */
pitch = bb; /* and a perfectly legal note */
count++;
}
look_ahead_and_toot(in_string);
break;
case 'D': /* D is like A */
case 'd':
pitch = dd;
if ((n_note == '#')||(n_note == '+')){
pitch = ds;
count++;
}
if (n_note == '-'){
pitch = cs; /* D flat is C sharp */
count++;
}
look_ahead_and_toot(in_string);
break;
case 'E': /* E is like A */
case 'e':
pitch = ee;
if ((n_note == '#')||(n_note == '+')){
pitch = ff; /* E sharp is F */
count++;
}
if (n_note == '-'){
pitch = ds;
count++;
}
look_ahead_and_toot(in_string);
break;
case 'F': /* F is like A */
case 'f':
pitch = ff;
if ((n_note == '#')||(n_note == '+')){
pitch = fs;
count++;
}
if (n_note == '-'){
pitch = ee;
count++;
}
look_ahead_and_toot(in_string);
break;
case 'G': /* G is like A */
case 'g':
pitch = gg;
if ((n_note == '#')||(pitch == '+')){
pitch = gs;
count++;
}
if (n_note == '-'){
pitch = fs;
count++;
}
look_ahead_and_toot(in_string);
break;
case 'L': /* set length */
case 'l':
if(temp_duration = check_length(in_string)){
duration = tempo/temp_duration;
length = temp_duration;
}
break;
case '>': /* go up an octave */
shift++;
break;
case '<': /* go down an octave */
shift--;
break;
case 'O': /* chose an octave */
case 'o':
temp_octave = n_note - '0';
if ((temp_octave < 0)||(temp_octave > 6)){
printf("octave out of range");
break;
}
switch(n_note){
case '0':
shift = -4;
break;
case '1':
shift = -3;
break;
case '2':
shift = -2;
break;
case '3':
shift = -1;
break;
case '4': /* default octave */
shift = 0;
break;
case '5':
shift = 1;
break;
case '6':
shift = 2;
break;
}
count++; /* advance over digit */
break;
case 'P': /* set pause/rest length */
case 'p': /* issue note of freq 0 to rest */
case 'R': /* computer scientists pause */
case 'r': /* but musicians rest! */
pitch = 0;
look_ahead_and_toot(in_string);
break;
case 'T': /* set tempo */
case 't':
temp_duration = check_integer(in_string);
if ((temp_duration < 32)||(temp_duration > 255))
break;
tempo = temp_duration*2;
duration = tempo/length;
break;
case ' ': /* spaces are gobbled up */
break;
default: /* had a problem so issue error */
printf("Syntax error in character %d \n",count);
goto terminate;
}
count++; /* advance pointer to next note */
}
terminate:
}
/* The trickiest part of the syntax are the optional trailers that
can follow each note. These include an optional integer that
specifies a quarter (4) or eighth note (8) (or any integer
between 1 and 64) and 1 or more optional dots, each of which
increases the current duration by half. This section parses
these trailers, and then uses the global variables that contain
the tempo and octave to compute the duration and pitch, and
then call note. Note that rests are handled as notes of 0 pitch.
*/
void look_ahead_and_toot(in_string)
char in_string[];
{
int temp_duration;
if (temp_duration = check_length(in_string)) /* if non zero have a temp */
temp_duration = tempo/temp_duration; /* compute new duration */
else
temp_duration = duration; /* if 0 play default duration */
/* check for dot, and if found call gobble_dots to increase temp_duration */
if (in_string[count+1] == '.')
temp_duration = gobble_dots(temp_duration,in_string);
/* range check octaves */
if (shift < -4)
shift = -4;
if (shift > 2)
shift = 2;
/* shift to change octaves */
if (shift < 0) /* negative shifts go down in frequency */
pitch = pitch >> -shift;
else /* positive shifts go up in frequency */
pitch = pitch << shift;
/* optional diagnostics for debugging */
printf("%c = %d duration = %d octave = d\n",
c_note,pitch,temp_duration,shift+4);
/* finally we are ready for a little toot */
note(pitch,temp_duration);
}
int gobble_dots(duration_in,in_string)
int duration_in;
char in_string[];
{
int duration_out;
int duration_increment;
duration_out = duration_in;
duration_increment = duration_in;
/* gobble as long as there are dots adding half the prior duration inc */
while (in_string[count+1] == '.'){
duration_increment = duration_increment >> 1; /* divide it by 2 */
duration_out = duration_out + duration_increment;
count++; /* advance string pointer */
}
return(duration_out);
}
/* returns 1-64 in range 1-64 else returns 0 */
int check_length(in_string)
char in_string[];
{
int result = check_integer(in_string);
if ((result < 1) || (result > 64))
return(0); /* out of range */
else
return(result); /* in range */
}
/* 0 1 to 999 if 1 - 999 found and advances count */
/* returns 0 otherwise */
int check_integer(in_string)
char in_string[];
{
int n_char,m_char,l_char;
n_char = in_string[count+1] - '0';
if ((n_char > 9) || (n_char < 0)) return (0); /* return if out of range */
count++; /* we found a digit so advance count */
m_char = in_string[count+1] - '0'; /* check next integer */
if ((m_char > 9) || (m_char < 0))
return (n_char);
else
count++; /*found second didit so advance again */
l_char = in_string[count+1] - '0';
if ((l_char > 9) || (l_char < 0)) /* check last possible digit */
return (n_char*10+m_char); /* compute 2 digit result */
else {
count++; /* we found a third and last digit */
return(n_char*100+m_char*10+l_char);
}
}
/* optional main program works as an interactive interpreter */
char note_string[120];
/*
main()
{
do{
puts("enter note ");
fflush(stdin);
gets(note_string);
printf("\nnote string = %s \n",note_string);
play();
} while (strlen(note_string) > 0);
}
*/
[EXAMPLE 1]
char *mapdev();
main()
{
int jcount = 0;
char *scr_ptr;
/* map the screen into the data segment */
scr_ptr = mapdev(0xb8000,4096);
while (jcount < 4096)
{
*(scr_ptr + (jcount++)) = 0x20; /* write space*/
*(scr_ptr + (jcount++)) = 0x7c; /* and attribute*/
}
}